package controller

import (
	"bytes"
	"gin_web/databases"
	"gin_web/model"
	"gin_web/utils"
	"github.com/dchest/captcha"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
	"net/http"
	"time"
)

type AuthController struct {
	DB *gorm.DB
}

func NewAuthController() *AuthController {
	db := databases.DB
	db.AutoMigrate(&model.User{})
	return &AuthController{DB: db}
}

func (a AuthController) Register(ctx *gin.Context) {
	user := model.User{}
	err := ctx.ShouldBind(&user)
	if err != nil {
		ctx.Error(err)
		return
	}
	result := a.DB.Where("user_name = ?", user.UserName).First(&user)
	if result.RowsAffected > 0 {
		utils.ErrorR(ctx, "用户已经注册")
		return
	}

	user.PassWord, err = utils.PasswordHash(user.PassWord)
	if err != nil {
		utils.ServerError(ctx, err)
		return
	}
	user.UserId = uuid.NewV4()
	a.DB.Save(&user)
	utils.SuccessR(ctx, nil, "注册成功")
}

func (a AuthController) Captcha(ctx *gin.Context) {
	l := captcha.DefaultLen
	w, h := 107, 36
	captchaId := captcha.NewLen(l)
	session := sessions.Default(ctx)
	session.Set("captcha", captchaId)
	_ = session.Save()
	_ = Serve(ctx.Writer, ctx.Request, captchaId, ".png", "zh", false, w, h)
}
func Serve(w http.ResponseWriter, r *http.Request, id, ext, lang string, download bool, width, height int) error {
	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
	w.Header().Set("Pragma", "no-cache")
	w.Header().Set("Expires", "0")

	var content bytes.Buffer
	switch ext {
	case ".png":
		w.Header().Set("Content-Type", "image/png")
		_ = captcha.WriteImage(&content, id, width, height)
	case ".wav":
		w.Header().Set("Content-Type", "audio/x-wav")
		_ = captcha.WriteAudio(&content, id, lang)
	default:
		return captcha.ErrNotFound
	}

	if download {
		w.Header().Set("Content-Type", "application/octet-stream")
	}
	http.ServeContent(w, r, id+ext, time.Time{}, bytes.NewReader(content.Bytes()))
	return nil
}

func (a AuthController) CaptchaVerify(ctx *gin.Context) {
	value := ctx.Param("value")
	if CaptchaVerify(ctx, value) {
		utils.SuccessR(ctx, nil, "验证成功")
	} else {
		utils.ErrorR(ctx, "验证失败")
	}
}

func (a AuthController) Login(ctx *gin.Context) {
	var formUser model.User
	var user model.User
	err := ctx.ShouldBind(&formUser)
	if err != nil {
		ctx.Error(err)
		return
	}
	result := a.DB.Where("user_name = ?", formUser.UserName).First(&user)
	if result.RowsAffected == 0 {
		utils.ErrorR(ctx, "用户不存在")
		return
	}

	if err := bcrypt.CompareHashAndPassword([]byte(user.PassWord), []byte(formUser.PassWord)); err != nil {
		utils.ErrorR(ctx, "密码错误")
		return
	}

	token, err := utils.GenerateJWT(user.UserName)
	if err != nil {
		utils.ErrorR(ctx, err.Error())
		return
	}
	utils.SuccessR(ctx, utils.NewTokenData(token), "登录成功")
}

func CaptchaVerify(ctx *gin.Context, code string) bool {
	session := sessions.Default(ctx)
	if captchaId := session.Get("captcha"); captchaId != nil {
		session.Delete("captcha")
		_ = session.Save()
		return captcha.VerifyString(captchaId.(string), code)
	}
	return false
}
